//
//  WmcRecognitionImageView.swift
//  YPWatermarkCamera
//
//  Created by 周诗松 on 2022/10/28.
//

import UIKit

class WmcRecognitionImageView: WmcBaseView {
    // Internal

    enum CropPosition: Int {
        case leftTop = 100
        case rightTop = 101
        case leftBottom = 102
        case rightBottom = 103
        case top = 104
        case left = 105
        case bottom = 106
        case right = 107
    }

    var updateCount: ((Int) -> Void)?

    override func makeUI() {
        isUserInteractionEnabled = true
        backgroundColor = .black

        addSubview(imgView)
        imgView.addSubview(cropView)
        cropView.addSubview(leftTopVView)
        cropView.addSubview(leftTopHView)
        cropView.addSubview(topRightHView)
        cropView.addSubview(topRightVView)
        cropView.addSubview(leftBottomVView)
        cropView.addSubview(leftBottomHView)
        cropView.addSubview(rightBottomVView)
        cropView.addSubview(rightBottomHView)
        cropView.addSubview(topView)
        cropView.addSubview(bottomView)
        cropView.addSubview(leftView)
        cropView.addSubview(rightView)

        cropView.addSubview(leftTopView)
        cropView.addSubview(rightTopView)
        cropView.addSubview(leftBottomView)
        cropView.addSubview(rightBottomView)
        cropView.addSubview(topConcealView)
        cropView.addSubview(bottomConcealView)
        cropView.addSubview(leftConcealView)
        cropView.addSubview(rightConcealView)

        imgView.snp.makeConstraints { make in
            make.left.top.equalTo(0)
            make.right.bottom.equalTo(0)
        }

        leftTopVView.snp.makeConstraints { make in
            make.left.equalTo(-borderWidth)
            make.top.equalTo(0)
            make.width.equalTo(borderWidth)
            make.height.equalTo(42)
        }

        leftTopHView.snp.makeConstraints { make in
            make.left.equalTo(-borderWidth)
            make.top.equalTo(-borderWidth)
            make.width.equalTo(48)
            make.height.equalTo(borderWidth)
        }

        topRightHView.snp.makeConstraints { make in
            make.top.equalTo(-borderWidth)
            make.right.equalTo(borderWidth)
            make.width.equalTo(48)
            make.height.equalTo(borderWidth)
        }

        topRightVView.snp.makeConstraints { make in
            make.top.equalTo(0)
            make.right.equalTo(borderWidth)
            make.width.equalTo(borderWidth)
            make.height.equalTo(42)
        }

        leftBottomVView.snp.makeConstraints { make in
            make.bottom.equalTo(0)
            make.left.equalTo(-borderWidth)
            make.width.equalTo(borderWidth)
            make.height.equalTo(42)
        }

        leftBottomHView.snp.makeConstraints { make in
            make.bottom.equalTo(borderWidth)
            make.left.equalTo(-borderWidth)
            make.width.equalTo(48)
            make.height.equalTo(borderWidth)
        }

        rightBottomVView.snp.makeConstraints { make in
            make.bottom.equalTo(0)
            make.right.equalTo(borderWidth)
            make.width.equalTo(borderWidth)
            make.height.equalTo(42)
        }

        rightBottomHView.snp.makeConstraints { make in
            make.bottom.equalTo(borderWidth)
            make.right.equalTo(borderWidth)
            make.width.equalTo(48)
            make.height.equalTo(borderWidth)
        }

        topView.snp.makeConstraints { make in
            make.top.equalTo(-borderWidth)
            make.centerX.equalToSuperview()
            make.width.equalTo(48)
            make.height.equalTo(borderWidth)
        }

        bottomView.snp.makeConstraints { make in
            make.bottom.equalTo(borderWidth)
            make.centerX.equalToSuperview()
            make.width.equalTo(48)
            make.height.equalTo(borderWidth)
        }

        leftView.snp.makeConstraints { make in
            make.left.equalTo(-borderWidth)
            make.centerY.equalToSuperview()
            make.width.equalTo(borderWidth)
            make.height.equalTo(48)
        }

        rightView.snp.makeConstraints { make in
            make.right.equalTo(borderWidth)
            make.centerY.equalToSuperview()
            make.width.equalTo(borderWidth)
            make.height.equalTo(48)
        }

        leftTopView.snp.makeConstraints { make in
            make.width.height.equalTo(20)
            make.left.top.equalTo(0)
        }

        rightTopView.snp.makeConstraints { make in
            make.width.height.equalTo(20)
            make.right.top.equalTo(0)
        }

        leftBottomView.snp.makeConstraints { make in
            make.width.height.equalTo(20)
            make.left.bottom.equalTo(0)
        }

        rightBottomView.snp.makeConstraints { make in
            make.width.height.equalTo(20)
            make.right.bottom.equalTo(0)
        }

        topConcealView.snp.makeConstraints { make in
            make.top.equalTo(0)
            make.centerX.equalToSuperview()
            make.width.equalTo(48)
            make.height.equalTo(10)
        }

        bottomConcealView.snp.makeConstraints { make in
            make.bottom.equalTo(0)
            make.centerX.equalToSuperview()
            make.width.equalTo(48)
            make.height.equalTo(10)
        }

        leftConcealView.snp.makeConstraints { make in
            make.left.equalTo(0)
            make.centerY.equalToSuperview()
            make.width.equalTo(10)
            make.height.equalTo(48)
        }

        rightConcealView.snp.makeConstraints { make in
            make.right.equalTo(0)
            make.centerY.equalToSuperview()
            make.width.equalTo(10)
            make.height.equalTo(48)
        }
    }

    func showRecognitionResult(list: [WmcMediaRecognitionModel], radius: Double) {
        self.radius = radius
        self.list = list
        addRecognitionMarkView(list: list, radius: radius)
    }

    func queryCropViewFrame() -> CGRect {
        return cropView.frame
    }

    func queryImgViewFrame() -> CGRect {
        return imgView.frame
    }

    func updateCropViewFrame(_ rect: CGRect) {
        cropView.frame = rect
        resetCropMask()
    }

    func updateAllMarkViewFrame(_ scale: Double) {
        markViewList.forEach { markView in
            markView.frame = CGRect(x: markView.frame.origin.x * scale, y: markView.frame.origin.y * scale, width: markView.frame.width * scale, height: markView.frame.height * scale)
        }

        customViewList.forEach { markView in
            markView.frame = CGRect(x: markView.frame.origin.x * scale, y: markView.frame.origin.y * scale, width: markView.frame.width * scale, height: markView.frame.height * scale)
        }

        resetMarkViewDisplay()
    }

    func updateImage(_ image: UIImage, bounds: CGRect) {
        imgView.image = image

        let imgHeight = image.size.height
        let imgWidth = image.size.width
        let ratio = Float(imgHeight) / Float(imgWidth)
        if ratio == 0 {
            return
        }
        var maxHeight = Float(bounds.height) - 20
        var maxWidth = maxHeight / ratio

        if maxWidth > Float(bounds.width) {
            maxWidth = Float(bounds.width)
            maxHeight = maxWidth * ratio
        }

        let leftMargin = (Float(bounds.width) - maxWidth) / 2.0
        imgView.snp.remakeConstraints { make in
            make.top.bottom.equalToSuperview()
            make.left.equalTo(leftMargin)
            make.right.equalTo(-leftMargin)
            make.width.equalTo(maxWidth)
            make.height.equalTo(maxHeight)
        }
    }

    func showCropViewDefalutRange() {
        layoutIfNeeded()

        var width = imgView.bounds.width
        var height = imgView.bounds.height

        if width < borderWidth {
            width = borderWidth
        }

        if height < borderWidth {
            height = borderWidth
        }
        cropView.frame = CGRect(x: borderWidth, y: borderWidth, width: width - borderWidth * 2, height: height - borderWidth * 2)

        cropView.isHidden = false
        resetCropMask()
    }

    func switchPureView(isPure: Bool) {
        imgView.subviews.forEach { subView in
            if !(subView is WmcRecognitionMarkView) {
                subView.isHidden = isPure
            }
        }
        maskLayer?.isHidden = isPure
    }

    // Private

    private let borderWidth: CGFloat = 3.0

    private var maskLayer: CAShapeLayer?
    private var radius: Double = 32.0
    private var list: [WmcMediaRecognitionModel] = []

    private let minCropWith = 100.0
    private let minCropHeight = 100.0

    private lazy var imgView: UIImageView = {
        let view = UIImageView()
        view.contentMode = .scaleAspectFit
        view.isUserInteractionEnabled = true
        let tap = UITapGestureRecognizer(target: self, action: #selector(tapMaskView(gesture:)))
        view.addGestureRecognizer(tap)
        return view
    }()

    private lazy var cropView: WmcRecognitionSpecialView = {
        let view = WmcRecognitionSpecialView(frame: CGRect(x: 0, y: 0, width: minCropWith, height: minCropHeight))
        view.backgroundColor = .clear
        view.isUserInteractionEnabled = true
        let gesture = UIPanGestureRecognizer(target: self, action: #selector(dragTheView(gesture:)))
        view.addGestureRecognizer(gesture)
        let tap = UITapGestureRecognizer(target: self, action: #selector(tapMaskView(gesture:)))
        view.addGestureRecognizer(tap)
        view.isHidden = true
        return view
    }()

    private lazy var leftTopVView: UIView = {
        let view = UIView()
        view.backgroundColor = .white
        view.tag = CropPosition.leftTop.rawValue
        view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(dragTheBorder(gesture:))))
        view.isUserInteractionEnabled = true
        return view
    }()

    private lazy var leftTopHView: UIView = {
        let view = UIView()
        view.backgroundColor = .white
        view.tag = CropPosition.leftTop.rawValue
        view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(dragTheBorder(gesture:))))
        view.isUserInteractionEnabled = true
        return view
    }()

    private lazy var leftTopView: UIView = {
        let view = UIView()
        view.backgroundColor = .clear
        view.tag = CropPosition.leftTop.rawValue
        view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(dragTheBorder(gesture:))))
        view.isUserInteractionEnabled = true
        return view
    }()

    private lazy var topRightHView: UIView = {
        let view = UIView()
        view.backgroundColor = .white
        view.tag = CropPosition.rightTop.rawValue
        view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(dragTheBorder(gesture:))))
        view.isUserInteractionEnabled = true
        return view
    }()

    private lazy var topRightVView: UIView = {
        let view = UIView()
        view.backgroundColor = .white
        view.tag = CropPosition.rightTop.rawValue
        view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(dragTheBorder(gesture:))))
        view.isUserInteractionEnabled = true
        return view
    }()

    private lazy var rightTopView: UIView = {
        let view = UIView()
        view.backgroundColor = .clear
        view.tag = CropPosition.rightTop.rawValue
        view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(dragTheBorder(gesture:))))
        view.isUserInteractionEnabled = true
        return view
    }()

    private lazy var leftBottomVView: UIView = {
        let view = UIView()
        view.backgroundColor = .white
        view.tag = CropPosition.leftBottom.rawValue
        view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(dragTheBorder(gesture:))))
        view.isUserInteractionEnabled = true
        return view
    }()

    private lazy var leftBottomHView: UIView = {
        let view = UIView()
        view.backgroundColor = .white
        view.tag = CropPosition.leftBottom.rawValue
        view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(dragTheBorder(gesture:))))
        view.isUserInteractionEnabled = true
        return view
    }()

    private lazy var leftBottomView: UIView = {
        let view = UIView()
        view.backgroundColor = .clear
        view.tag = CropPosition.leftBottom.rawValue
        view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(dragTheBorder(gesture:))))
        view.isUserInteractionEnabled = true
        return view
    }()

    private lazy var rightBottomVView: UIView = {
        let view = UIView()
        view.backgroundColor = .white
        view.tag = CropPosition.rightBottom.rawValue
        view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(dragTheBorder(gesture:))))
        view.isUserInteractionEnabled = true
        return view
    }()

    private lazy var rightBottomHView: UIView = {
        let view = UIView()
        view.backgroundColor = .white
        view.tag = CropPosition.rightBottom.rawValue
        view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(dragTheBorder(gesture:))))
        view.isUserInteractionEnabled = true
        return view
    }()

    private lazy var rightBottomView: UIView = {
        let view = UIView()
        view.backgroundColor = .clear
        view.tag = CropPosition.rightBottom.rawValue
        view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(dragTheBorder(gesture:))))
        view.isUserInteractionEnabled = true
        return view
    }()

    private lazy var topView: UIView = {
        let view = UIView()
        view.backgroundColor = .white
        view.tag = CropPosition.top.rawValue
        view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(dragTheBorder(gesture:))))
        view.isUserInteractionEnabled = true
        return view
    }()

    private lazy var topConcealView: UIView = {
        let view = UIView()
        view.backgroundColor = .clear
        view.tag = CropPosition.top.rawValue
        view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(dragTheBorder(gesture:))))
        view.isUserInteractionEnabled = true
        return view
    }()

    private lazy var bottomView: UIView = {
        let view = UIView()
        view.backgroundColor = .white
        view.tag = CropPosition.bottom.rawValue
        view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(dragTheBorder(gesture:))))
        view.isUserInteractionEnabled = true
        return view
    }()

    private lazy var bottomConcealView: UIView = {
        let view = UIView()
        view.backgroundColor = .clear
        view.tag = CropPosition.bottom.rawValue
        view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(dragTheBorder(gesture:))))
        view.isUserInteractionEnabled = true
        return view
    }()

    private lazy var leftView: UIView = {
        let view = UIView()
        view.backgroundColor = .white
        view.tag = CropPosition.left.rawValue
        view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(dragTheBorder(gesture:))))
        view.isUserInteractionEnabled = true
        return view
    }()

    private lazy var leftConcealView: UIView = {
        let view = UIView()
        view.backgroundColor = .clear
        view.tag = CropPosition.left.rawValue
        view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(dragTheBorder(gesture:))))
        view.isUserInteractionEnabled = true
        return view
    }()

    private lazy var rightView: UIView = {
        let view = UIView()
        view.backgroundColor = .white
        view.tag = CropPosition.right.rawValue
        view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(dragTheBorder(gesture:))))
        view.isUserInteractionEnabled = true
        return view
    }()

    private lazy var rightConcealView: UIView = {
        let view = UIView()
        view.backgroundColor = .clear
        view.tag = CropPosition.right.rawValue
        view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(dragTheBorder(gesture:))))
        view.isUserInteractionEnabled = true
        return view
    }()

    private var markViewList: [WmcRecognitionMarkView] = []

    private var customViewList: [WmcRecognitionMarkView] = []

    private func resetCropMask() {
        let path = UIBezierPath(rect: imgView.bounds)
        let clearPath = UIBezierPath(rect: cropView.frame)
        path.append(clearPath)

        let layer = CAShapeLayer()
        layer.frame = imgView.bounds
        layer.fillColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.5).cgColor
        layer.strokeColor = UIColor.clear.cgColor
        layer.fillRule = .evenOdd
        layer.path = path.cgPath
        for item in imgView.layer.sublayers ?? [] {
            if item is CAShapeLayer {
                item.removeFromSuperlayer()
            }
        }
        imgView.layer.insertSublayer(layer, at: 0)

        maskLayer = layer

        resetMarkViewDisplay()
    }

    private func addRecognitionMarkView(list: [WmcMediaRecognitionModel], radius: Double) {
        let imgHeight = imgView.image?.size.height ?? 0
        if imgHeight == 0 {
            return
        }
        let scale = imgView.bounds.height / imgHeight
        for (idx, item) in list.enumerated() {
            let radiusValue = item.radius * scale
            let diameter = radiusValue * 2.0
            let fontSize = diameter * 0.5
            let view = WmcRecognitionMarkView(style: .recognition, radius: radiusValue, index: idx + 1, fontSize: fontSize)
            view.bounds = CGRect(x: 0, y: 0, width: diameter, height: diameter)
            view.center = CGPoint(x: item.centerPoint.x * scale, y: item.centerPoint.y * scale)
            imgView.addSubview(view)
            view.sendSubviewToBack(imgView)

            markViewList.append(view)
        }

        imgView.bringSubviewToFront(cropView)
    }

    private func resetMarkViewDisplay() {
        var idx: Int = 0
        markViewList.forEach { markView in
            let cropViewRect = CGRect(x: cropView.frame.origin.x - borderWidth, y: cropView.frame.origin.y - borderWidth, width: cropView.frame.width + borderWidth * 2, height: cropView.frame.height + borderWidth * 2)
            let isContain = isContainSubView(viewRect: cropViewRect, subViewRect: markView.frame)
            markView.isHidden = !isContain
            if isContain {
                idx += 1
                markView.setIndexLabel(idx)
            }
        }

        customViewList.forEach { markView in
            idx += 1
            markView.setIndexLabel(idx)
        }

        updateCount?(idx)
    }

    private func isContainSubView(viewRect: CGRect, subViewRect: CGRect) -> Bool {
        let topPoint = CGPoint(x: subViewRect.origin.x + subViewRect.width / 2.0, y: subViewRect.origin.y)
        let bottomPoint = CGPoint(x: subViewRect.origin.x + subViewRect.width / 2.0, y: subViewRect.origin.y + subViewRect.height)
        let leftPoint = CGPoint(x: subViewRect.origin.x, y: subViewRect.origin.y + subViewRect.height / 2.0)
        let rightPoint = CGPoint(x: subViewRect.origin.x + subViewRect.width, y: subViewRect.origin.y + subViewRect.height / 2.0)
        let result = viewRect.contains(topPoint) && viewRect.contains(bottomPoint) && viewRect.contains(leftPoint) && viewRect.contains(rightPoint)
        return result
    }

    @objc
    private func dragTheView(gesture: UIPanGestureRecognizer) {
        switch gesture.state {
        case .changed:
            let point = gesture.translation(in: imgView)

            var centerX = cropView.center.x + point.x
            var centerY = cropView.center.y + point.y

            let leftMargin = cropView.bounds.width / 2.0 + borderWidth
            let rightMargin = imgView.bounds.width - cropView.bounds.width / 2.0 - borderWidth
            let topMargin = cropView.bounds.height / 2.0 + borderWidth
            let bottomMargin = imgView.bounds.height - cropView.bounds.height / 2.0 - borderWidth

            if centerX < leftMargin {
                centerX = leftMargin
            }

            if centerX > rightMargin {
                centerX = rightMargin
            }

            if centerY < topMargin {
                centerY = topMargin
            }

            if centerY > bottomMargin {
                centerY = bottomMargin
            }

            cropView.center = CGPoint(x: centerX, y: centerY)
            resetCropMask()
        default: break
        }

        gesture.setTranslation(.zero, in: imgView)
    }

    @objc
    private func dragTheBorder(gesture: UIPanGestureRecognizer) {
        guard let panView = gesture.view else { return }

        var point = gesture.location(in: imgView)
        if point.x < borderWidth {
            point.x = borderWidth
        }
        if point.x > imgView.frame.width - borderWidth {
            point.x = imgView.frame.width - borderWidth
        }
        if point.y < borderWidth {
            point.y = borderWidth
        }
        if point.y > imgView.frame.height - borderWidth {
            point.y = imgView.frame.height - borderWidth
        }

        if gesture.state == .changed {
            if panView.tag == CropPosition.leftTop.rawValue {
                var frame = cropView.frame
                let minX: CGFloat = borderWidth
                let minY: CGFloat = borderWidth
                let maxX = frame.maxX - CGFloat(minCropWith)
                let maxY = frame.maxY - CGFloat(minCropHeight)
                var x = point.x
                if x < minX {
                    x = minX
                }
                if x > maxX {
                    x = maxX
                }
                var y = point.y
                if y < minY {
                    y = minY
                }
                if y > maxY {
                    y = maxY
                }
                frame = CGRect(x: x, y: y, width: (frame.origin.x - x) + frame.width, height: (frame.origin.y - y) + frame.height)
                cropView.frame = frame
                resetCropMask()
            } else if panView.tag == CropPosition.left.rawValue {
                var frame = cropView.frame
                let minX: CGFloat = borderWidth
                let maxX = frame.maxX - CGFloat(minCropWith)
                var x = point.x
                if x < minX {
                    x = minX
                }
                if x > maxX {
                    x = maxX
                }
                frame = CGRect(x: x, y: frame.origin.y, width: (frame.origin.x - x) + frame.width, height: frame.height)
                cropView.frame = frame
                resetCropMask()
            } else if panView.tag == CropPosition.leftBottom.rawValue {
                var frame = cropView.frame
                let minX: CGFloat = borderWidth
                let minY: CGFloat = frame.minY + CGFloat(minCropHeight)
                let maxX = frame.maxX - CGFloat(minCropWith)
                let maxY = imgView.frame.height
                var x = point.x
                if x < minX {
                    x = minX
                }
                if x > maxX {
                    x = maxX
                }
                var y = point.y
                if y < minY {
                    y = minY
                }
                if y > maxY {
                    y = maxY
                }
                frame = CGRect(x: x, y: frame.origin.y, width: (frame.origin.x - x) + frame.width, height: y - frame.origin.y)
                cropView.frame = frame
                resetCropMask()
            } else if panView.tag == CropPosition.top.rawValue {
                var frame = cropView.frame
                let minY: CGFloat = 0.0
                let maxY = frame.maxY - CGFloat(minCropHeight)
                var y = point.y
                if y < minY {
                    y = minY
                }
                if y > maxY {
                    y = maxY
                }
                frame = CGRect(x: frame.origin.x, y: y, width: frame.width, height: (frame.origin.y - y) + frame.height)
                cropView.frame = frame
                resetCropMask()
            } else if panView.tag == CropPosition.rightTop.rawValue {
                var frame = cropView.frame
                let minX: CGFloat = frame.minX + CGFloat(minCropWith)
                let minY: CGFloat = 0.0
                let maxX = imgView.frame.width
                let maxY = frame.maxY - CGFloat(minCropHeight)
                var x = point.x
                if x < minX {
                    x = minX
                }
                if x > maxX {
                    x = maxX
                }
                var y = point.y
                if y < minY {
                    y = minY
                }
                if y > maxY {
                    y = maxY
                }
                frame = CGRect(x: frame.origin.x, y: y, width: x - frame.origin.x, height: (frame.origin.y - y) + frame.height)
                cropView.frame = frame
                resetCropMask()
            } else if panView.tag == CropPosition.right.rawValue {
                var frame = cropView.frame
                let minX: CGFloat = frame.minX + CGFloat(minCropWith)
                let maxX = imgView.frame.width
                var x = point.x
                if x < minX {
                    x = minX
                }
                if x > maxX {
                    x = maxX
                }
                frame = CGRect(x: frame.origin.x, y: frame.origin.y, width: x - frame.origin.x, height: frame.height)
                cropView.frame = frame
                resetCropMask()
            } else if panView.tag == CropPosition.rightBottom.rawValue {
                var frame = cropView.frame
                let minX: CGFloat = frame.minX + CGFloat(minCropWith)
                let minY: CGFloat = frame.minY + CGFloat(minCropWith)
                let maxX = imgView.frame.width
                let maxY = imgView.frame.height
                var x = point.x
                if x < minX {
                    x = minX
                }
                if x > maxX {
                    x = maxX
                }
                var y = point.y
                if y < minY {
                    y = minY
                }
                if y > maxY {
                    y = maxY
                }
                frame = CGRect(x: frame.origin.x, y: frame.origin.y, width: x - frame.origin.x, height: y - frame.origin.y)
                cropView.frame = frame
                resetCropMask()
            } else if panView.tag == CropPosition.bottom.rawValue {
                var frame = cropView.frame
                let minY: CGFloat = frame.minY + CGFloat(minCropHeight)
                let maxY = imgView.frame.height
                var y = point.y
                if y < minY {
                    y = minY
                }
                if y > maxY {
                    y = maxY
                }
                frame = CGRect(x: frame.origin.x, y: frame.origin.y, width: frame.width, height: y - frame.origin.y)
                cropView.frame = frame
                resetCropMask()
            }
        }
    }

    @objc
    private func tapMaskView(gesture: UITapGestureRecognizer) {
        let point = gesture.location(in: imgView)
        var tapViewList: [WmcRecognitionMarkView] = []

        markViewList.forEach { markView in
            if !markView.isHidden, markView.frame.contains(point) {
                tapViewList.append(markView)
            }
        }

        customViewList.forEach { markView in
            if markView.frame.contains(point) {
                tapViewList.append(markView)
            }
        }

        if tapViewList.isEmpty {
            let index = queryMarkViewCount() + customViewList.count + 1

            let imgHeight = imgView.image?.size.height ?? 0
            if imgHeight == 0 {
                return
            }
            let scale = imgView.bounds.height / imgHeight

            let radiusValue = radius * scale

            let minX = point.x - radiusValue
            let maxX = point.x + radiusValue
            let minY = point.y - radiusValue
            let maxY = point.y + radiusValue

            if minX < 0 || minY < 0 || maxX > imgView.bounds.width || maxY > imgView.bounds.height {
                return
            }

            let diameter = radiusValue * 2.0
            let fontSize = diameter * 0.5

            let view = WmcRecognitionMarkView(style: .custom, radius: radiusValue, index: index, fontSize: fontSize)
            view.bounds = CGRect(x: 0, y: 0, width: diameter, height: diameter)
            view.center = CGPoint(x: point.x, y: point.y)
            imgView.addSubview(view)
            view.sendSubviewToBack(imgView)

            customViewList.append(view)

            imgView.bringSubviewToFront(cropView)

            updateCount?(index)
        } else {
            guard let view = tapViewList.last else { return }
            view.removeFromSuperview()
            tapViewList.removeLast()

            let idx1 = markViewList.firstIndex { markView in
                return view == markView
            }

            if let idx = idx1 {
                markViewList.remove(at: idx)
            }

            let idx2 = customViewList.firstIndex { markView in
                return view == markView
            }

            if let idx = idx2 {
                customViewList.remove(at: idx)
            }

            var idx: Int = 0
            markViewList.forEach { markView in
                if !markView.isHidden {
                    idx += 1
                    markView.setIndexLabel(idx)
                }
            }

            customViewList.forEach { markView in
                idx += 1
                markView.setIndexLabel(idx)
            }

            updateCount?(idx)
        }
    }

    private func queryMarkViewCount() -> Int {
        var count: Int = 0
        markViewList.forEach { markView in
            if !markView.isHidden {
                count += 1
            }
        }
        return count
    }
}
